Arrowheads
Volume Number: 1
Issue Number: 9
Column Tag: C WORKSHOP
How to Draw Arrowheaded Lines
How to Draw Arrowheaded Lines
While writing a new application, I discovered I needed to have lines with
arrowheads (like the ones we all love in MacDraw). Not only that, I needed to have the
line stop on the surface of an object (usually an oval or rectangle).
The first place to look, of course, is to see how MacDraw did it. After using
MacDraw for some time in various applications, I was surprised to see that the
arrowheads were not 3-pointed polygons but actually small wedges! This was
discovered after placing an arrowhead on a thick line and noticing the curvature of the
arrowhead.
Keeping with the Macintosh spirit, I decided to make the call similar to the ones
used in QuickDraw (i.e. - Line and LineTo). Instead of using a LineTo call, this routine
may be substituted and all of the LineTo's changed to ArrowLineTo's.
The parameter passed to it is the absolute horizontal and vertical coordinates of
the end point of the line (as in LineTo). The end point is also where the arrowhead will
be drawn.
The basic algorithm is simple -
1). Compute the slope of the line
2). Draw the line
3). Point the wedge in the opposite direction of the line (to create the effect of an
arrowhead).
4). Draw the wedge
There is a fantastic Mac routine called PtToAngle that will compute the angle for
you! All you need to do is to place a rectangle around the starting point, make the call,
and the angle is returned to you (in degrees)!
The following code (written in Mac C) is pretty much self explanatory. You could
experiment with the constants arrowWidth and arrowLength (as shown in Fig. 1) to
vary the width and length of the arrowhead. Note - this routine could be changed so that
these constants are passed as parameters, for applications that need varying sizes of
arrowheads.
/********************************************************************.
***
ArrowLineTo.c
Copyright 1985, FlottWare
**********************************************************************
**/
#include "MacCDefs.h" // Mac ROM data structure definitions
#include "Events.h
#include "Window.h
extern struct P_Str *CtoPstr();
int strlen(str) char *str;
{int i=0; while (str[i++]); return i-1;}

/*-------------------------------------------------------------------*
----
Global Data

----------------------------------------------------------------------
--*/
#define False 0
#define True 0xFF
Rect windowRect = {40,4,336,508}; // Window Rectangle
WindowPtr windowPtr; // Window Pointer
EventRecord event; // Current event record
/*--------------------------------------------------------------------
----
main()

----------------------------------------------------------------------
--*/
main()
{

if (CatchSignal()) // Is the user quitting this
application?
ExitToShell(); // Go to Finder when done

init(); // Init Mac
while (True) // Poll events forever
{
SystemTask(); // Perform System duties

if (GetNextEvent(everyEvent, & event)) // Get the next event
{

switch ( event.what ) // Which event is it?
{
case autoKey:
case keyDown: // Key was pressed
case mouseDown: // Mouse Button pressed
{
Signal("All Done"); // Y - quit application
break;
} // case autoKey,keyDown,mouseDown:

} // switch ( event.what)
} // if (Get event)
} // while (true)
} // main

/********************************************************************-
***
**********************************************************************
*/
/*-------------------------------------------------------------------*
--
init() -

----------------------------------------------------------------------
*/
init()
{
// Open a window

windowPtr = NewWindow(0,& windowRect,CtoPstr("Hit Key or Mouse to
Quit"),True,
documentProc,-1,True,0);
SetPort( windowPtr);

#define centerH 250
#define centerV 150
#define offset 50
// Draw some lines with arrowheads

MoveTo(centerH,centerV);
ArrowLineTo(centerH-offset,centerV);

MoveTo(centerH,centerV);
ArrowLineTo(centerH-offset,centerV+offset);

MoveTo(centerH,centerV);
ArrowLineTo(centerH,centerV+offset);

MoveTo(centerH,centerV);
ArrowLineTo(centerH+offset,centerV+offset);

MoveTo(centerH,centerV);
ArrowLineTo(centerH+offset,centerV);

MoveTo(centerH,centerV);
ArrowLineTo(centerH+offset,centerV-offset);

MoveTo(centerH,centerV);
ArrowLineTo(centerH,centerV-offset);

MoveTo(centerH,centerV);
ArrowLineTo(centerH-offset,centerV-offset);

} // end init()
/*-------------------------------------------------------------------i
--
ArrowLineTo(horiz,vert)

This routine draws a line from the current pen location
to point (h,v) with an arrowhead (wedge) on the end of it.
Inputs : horiz - horizontal coord of end point
vert - vertical coord of end point
Written by: Rick Flott Mac C (Consulair) V
1.0
---------------------------------------------------------------------.
*/
ArrowLineTo(horiz,vert)
short horiz;
short vert;
{
// Size of starting Rect used in PtToAngle
#define rectOffset 30
// Arrowhead (wedge) constants
// arrowWidth - width of 1/2 arrowhead (in degrees)
// arrowLength - length of arrowhead in pixels
#define arrowWidth 25
#define arrowLength 10

// Rects used in angle calculations
Rect startRect; // starting Rect used in PtToAngle
Rect arrowheadRect; // the Rect that the wedge is drawn in
short arrowAngle; // Angle of arrowhead (in degrees)

Point startPt,endPt; // Start,End points of line

GetPen(&startPt); // Get the current pen location
// Set up a rectangle around the starting point
// (this is needed for the PtToAngle routine)
SetRect (&startRect,startPt.h - rectOffset,
startPt.v - rectOffset,
startPt.h + rectOffset,
startPt.v + rectOffset);

SetPt(&endPt,horiz,vert); // Set up the end point

// Calculate the angle (in degrees) of the line
segment
PtToAngle(&startRect,&endPt,&arrowAngle);

LineTo(horiz,vert); // Draw the line

arrowAngle -= (180 + arrowWidth); // Create a arrowhead with a
wedge facing the opposite direction
// Set up a Rect for the wedge around the endpoint
SetRect (&arrowheadRect,endPt.h - arrowLength,
endPt.v - arrowLength,
endPt.h + arrowLength,
endPt.v + arrowLength);

// Draw arrow head (a reversed wedge)
PaintArc(&arrowheadRect,arrowAngle,2*arrowWidth);

} // end ArrowLineTo()